package org.ggumm21.gdata;

import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetQuery;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.client.spreadsheet.WorksheetQuery;
import com.google.gdata.data.Link;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.batch.BatchOperationType;
import com.google.gdata.data.batch.BatchStatus;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.data.docs.DocumentListEntry;
import com.google.gdata.data.spreadsheet.Cell;
import com.google.gdata.data.spreadsheet.CellEntry;
import com.google.gdata.data.spreadsheet.CellFeed;
import com.google.gdata.data.spreadsheet.ListEntry;
import com.google.gdata.data.spreadsheet.ListFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * An application that serves as a sample to show how the SpreadsheetService can
 * be used to import delimited text file to a spreadsheet.
 * 
 * 
 */
public class SpreadsheetClient {

	private SpreadsheetService service;

	private FeedURLFactory factory;
	
	private String username;
	private String password;

	private static final String APP_NAME = "org.ggumm21.gdata";
	
	private SpreadsheetClient() throws Exception {
		factory = FeedURLFactory.getDefault();
		service = new SpreadsheetService(APP_NAME);
	}

	/**
	 * Creates a client object for which the provided username and password
	 * produces a valid authentication.
	 * 
	 * @param username
	 *            the Google service user name
	 * @param password
	 *            the corresponding password for the user name
	 * @throws Exception
	 *             if error is encountered, such as invalid username and
	 *             password pair
	 */
	public SpreadsheetClient(String username, String password) throws Exception {
		this();
		service.setUserCredentials(username, password);
		service.setProtocolVersion(SpreadsheetService.Versions.V1);
		this.username = username;
		this.password = password;
	}

	public SpreadsheetClient(String username, String password,
			String captchaToken, String captchaAnswer) throws Exception {
		this();
		this.username = username;
		this.password = password;
		service.setUserCredentials(username, password, captchaToken,
				captchaAnswer);
	}

	public CellFeed getCellFeed(String bookName, String sheetName)
			throws Exception {
		WorksheetEntry sheet = getWorksheet(bookName, sheetName);
		return getCellFeed(sheet);
	}

	/**
	 * Gets the SpreadsheetEntry for the first spreadsheet with that name
	 * retrieved in the feed.
	 * 
	 * @param spreadsheet
	 *            the name of the spreadsheet
	 * @return the first SpreadsheetEntry in the returned feed, so latest
	 *         spreadsheet with the specified name
	 * @throws Exception
	 *             if error is encountered, such as no spreadsheets with the
	 *             name
	 */
	public SpreadsheetEntry getSpreadsheet(String spreadsheet) throws Exception {

		SpreadsheetQuery spreadsheetQuery = new SpreadsheetQuery(factory
				.getSpreadsheetsFeedUrl());
		spreadsheetQuery.setTitleQuery(spreadsheet);
		SpreadsheetFeed spreadsheetFeed = service.query(spreadsheetQuery,
				SpreadsheetFeed.class);
		List<SpreadsheetEntry> spreadsheets = spreadsheetFeed.getEntries();
		if (spreadsheets.isEmpty()) {
			throw new Exception("No spreadsheets with that name");
		}

		return spreadsheets.get(0);
	}

	/**
	 * Get the WorksheetEntry for the worksheet in the spreadsheet with the
	 * specified name.
	 * 
	 * @param spreadsheet
	 *            the name of the spreadsheet
	 * @param worksheet
	 *            the name of the worksheet in the spreadsheet
	 * @return worksheet with the specified name in the spreadsheet with the
	 *         specified name
	 * @throws Exception
	 *             if error is encountered, such as no spreadsheets with the
	 *             name, or no worksheet wiht the name in the spreadsheet
	 */
	public WorksheetEntry getWorksheet(String spreadsheet, String worksheet)
			throws Exception {

		SpreadsheetEntry spreadsheetEntry = getSpreadsheet(spreadsheet);

		WorksheetQuery worksheetQuery = new WorksheetQuery(spreadsheetEntry
				.getWorksheetFeedUrl());

		worksheetQuery.setTitleQuery(worksheet);
		WorksheetFeed worksheetFeed = service.query(worksheetQuery,
				WorksheetFeed.class);
		List<WorksheetEntry> worksheets = worksheetFeed.getEntries();
		if (worksheets.isEmpty()) {
			throw new Exception("No worksheets with that name in spreadhsheet "
					+ spreadsheetEntry.getTitle().getPlainText());
		}

		WorksheetEntry worksheetEntry = worksheets.get(0);

		return worksheetEntry;
	}

	public CellFeed getCellFeed(WorksheetEntry sheet) 
		throws IOException, ServiceException {
		URL feedUrl = sheet.getCellFeedUrl();
		CellFeed feed = service.getFeed(feedUrl, CellFeed.class);

		return feed;
	}

	public List<BatchStatus> processBatch(WorksheetEntry sheet,
			Cell[] value) throws IOException, ServiceException {

		URL cellFeedUrl = sheet.getCellFeedUrl();
		CellFeed feed = getCellFeed(sheet);
		
		CellFeed batchRequest = new CellFeed();
		List<CellEntry> entries = batchRequest.getEntries();
		Link batchLink = feed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
		URL batchUrl = new URL(batchLink.getHref());

		List<BatchStatus> batchErrors = new ArrayList<BatchStatus>();

		for (int i = 0; i < value.length; i++) {
			int row = value[i].getRow();
			int col = value[i].getCol();
			String batchId = "R" + row + "C" + col;
			if (batchId.equals("R5C26")) {
				System.out.println("xxx");
			}
			URL entryUrl = new URL(cellFeedUrl.toString() + "/" + batchId);
			CellEntry entry = service.getEntry(entryUrl, CellEntry.class);
			entry.changeInputValueLocal(value[i].getInputValue());
			BatchUtils.setBatchId(entry, batchId);
			BatchUtils.setBatchOperationType(entry, BatchOperationType.UPDATE);
			entries.add(entry);
			if (i % 9 == 0) {
				CellFeed batchResponse = null;
				try {
					batchResponse = service.batch(batchUrl, batchRequest);
				} catch(Exception ex) {
					return null;
				}
				for (CellEntry entry1 : batchResponse.getEntries()) {
					if (!BatchUtils.isSuccess(entry1)) {
						batchErrors.add(BatchUtils.getBatchStatus(entry1));
					}
				}
				entries.clear();
			}
			
		}
		if (entries.size() > 0) {
			CellFeed batchResponse = service.batch(batchUrl, batchRequest);

			for (CellEntry entry1 : batchResponse.getEntries()) {
				if (!BatchUtils.isSuccess(entry1)) {
					batchErrors.add(BatchUtils.getBatchStatus(entry1));
				}
			}			
		}

		return batchErrors;
	}

	public WorksheetEntry createWorksheet(String bookName,
			String sheetName) throws Exception {
		return createWorksheet(bookName, sheetName, 100, 30);
	}

	public WorksheetEntry createWorksheet(String bookName,
			String sheetName, int rowCount, int colCount) 
		throws Exception {
		
		SpreadsheetEntry spreadsheet = getSpreadsheet(bookName);
		
		WorksheetEntry worksheet = new WorksheetEntry();
		worksheet.setTitle(new PlainTextConstruct(sheetName));
		worksheet.setRowCount(rowCount);
		worksheet.setColCount(colCount);
		return service.insert(spreadsheet.getWorksheetFeedUrl(), worksheet);
	}

	public DocumentListEntry createSpreadsheet(String bookName, String user, String pass) 
		throws DocumentListException, MalformedURLException, IOException, ServiceException {
		DocumentList docList = new DocumentList(APP_NAME);
		docList.login(username, password);
		DocumentListEntry docEntry = docList.createNew(bookName, "spreadsheet");
		return docEntry;
		
	}
	
}
